<template>
  <Teleport to="body">
    <div
      v-if="visible"
      class="fixed inset-0 z-50 flex items-center justify-center p-4"
      @click="handleBackdropClick"
    >
      <!-- 自定义遮罩层 -->
      <slot name="backdrop">
        <div class="absolute inset-0 bg-black/50 backdrop-blur-sm" :class="backdropClass"></div>
      </slot>

      <!-- 弹窗内容 -->
      <div
        class="relative w-full bg-base-100 rounded-2xl shadow-2xl border border-base-300/30 overflow-hidden"
        :class="[modalClass, sizeClass]"
        @click.stop
      >
        <!-- 自定义头部 -->
        <slot name="header" :close="handleClose">
          <!-- 默认不显示头部 -->
        </slot>

        <!-- 自定义内容区域 -->
        <slot name="content" :close="handleClose">
          <div class="p-6">
            <slot>
              <div class="text-center py-8">
                <div class="text-4xl mb-4">📝</div>
                <p class="text-base-content/70">请添加内容</p>
              </div>
            </slot>
          </div>
        </slot>

        <!-- 自定义底部 -->
        <slot name="footer" :close="handleClose">
          <!-- 默认不显示底部 -->
        </slot>
      </div>
    </div>
  </Teleport>
</template>

<script setup lang="ts">
import { computed, watch, onUnmounted } from 'vue'

/**
 * 通用弹窗组件
 * 支持多种尺寸、样式和交互方式
 */

interface ModalProps {
  /** 是否显示弹窗 */
  visible?: boolean
  /** 弹窗尺寸 */
  size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | 'full'
  /** 是否点击遮罩关闭 */
  maskClosable?: boolean
  /** 是否按ESC键关闭 */
  escClosable?: boolean
  /** 自定义样式类 */
  customClass?: string
  /** 自定义遮罩层样式类 */
  backdropClass?: string
}

interface ModalEvents {
  /** 关闭事件 */
  close: []
  /** 显示事件 */
  show: []
  /** 隐藏事件 */
  hide: []
  /** 更新visible状态 */
  'update:visible': [value: boolean]
}

const props = withDefaults(defineProps<ModalProps>(), {
  visible: false,
  size: 'md',
  maskClosable: true,
  escClosable: true,
  customClass: '',
  backdropClass: '',
})

const emit = defineEmits<ModalEvents>()

// 尺寸样式映射
const sizeClass = computed(() => {
  const sizeMap = {
    xs: 'max-w-xs',
    sm: 'max-w-sm',
    md: 'max-w-md',
    lg: 'max-w-lg',
    xl: 'max-w-xl',
    '2xl': 'max-w-2xl',
    '3xl': 'max-w-3xl',
    '4xl': 'max-w-4xl',
    '5xl': 'max-w-5xl',
    '6xl': 'max-w-6xl',
    full: 'max-w-full mx-4',
  }
  return sizeMap[props.size]
})

// 合并样式类
const modalClass = computed(() => {
  return [props.customClass].filter(Boolean).join(' ')
})

// 处理关闭
const handleClose = () => {
  emit('close')
  emit('update:visible', false)
}

// 处理背景点击
const handleBackdropClick = () => {
  if (props.maskClosable) {
    handleClose()
  }
}

// 监听ESC键
const handleKeydown = (event: KeyboardEvent) => {
  if (event.key === 'Escape' && props.escClosable && props.visible) {
    handleClose()
  }
}

// 监听显示状态变化
watch(
  () => props.visible,
  (newVisible) => {
    if (newVisible) {
      emit('show')
      document.addEventListener('keydown', handleKeydown)
      document.body.style.overflow = 'hidden'
    } else {
      emit('hide')
      document.removeEventListener('keydown', handleKeydown)
      document.body.style.overflow = ''
    }
  },
  { immediate: true },
)

// 组件卸载时清理
onUnmounted(() => {
  document.removeEventListener('keydown', handleKeydown)
  document.body.style.overflow = ''
})
</script>

<style scoped>
/* 自定义滚动条 */
::-webkit-scrollbar {
  width: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: hsl(var(--bc) / 0.2);
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: hsl(var(--bc) / 0.3);
}
</style>
